﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;

namespace Fish_Atlantis.ProfessorPanel
{
  public partial class HealthyGrading : System.Web.UI.Page
  {
    public static readonly string[] MONTHS = new string[] { null, "一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月" };
    private static Risk NULL;
    static HealthyGrading()
    {
      NULL = new Risk(new Fishery(0, string.Empty, string.Empty, string.Empty));
    }
    
    public int Month;
    public DateTime Time;
    public bool Saved;
    public bool Published;
    public int PublishedCount;
    public string Location;
    public string Category;
    public IEnumerable<string> Locations;
    public IEnumerable<string> Categories;
    private Dictionary<int, Risk> EditingDictionary;
    private Dictionary<int, Fishery> FisheriesDictionary;
    private Dictionary<int, Risk> Risks;

    public IEnumerable<Fishery> Fisheries
    { get { return FisheriesDictionary.Values; } }
    public IEnumerable<Risk> Editing
    { get { return EditingDictionary.Values; } }

    protected void Page_Load(object sender, EventArgs e)
    {
      Time = DateTime.Now;
      Month = Time.Month;
      using (var con = Helper.GetConnection())
      {
        con.Open();
        string action = Page.IsPostBack ? Request["action"] : null;
        if (action == "Save" || action == "Publish") Save(con);
        InitFisheries(con);
        if (action == "Publish") Publish(con);
        con.Close();
      }
    }
    private DataTable GetData(SqlConnection con)
    {
      StringBuilder sql = new StringBuilder("SELECT Fishery.FisheryID, FisheryName, Category, Location, Month, Risk_Rank, Comment FROM Fishery INNER JOIN Risk ON Fishery.FisheryID = Risk.FisheryID");
      if (Page.IsPostBack && Request["action"] == "Filter")
      {
        Category = Request["category"];
        Location = Request["location"];
        if (Category != "-")
        {
          if (Location == "-") sql.AppendFormat(@" WHERE Category = '{0}'", Category);
          else
          {
            sql.AppendFormat(@" WHERE Category = '{0}' AND Location = '{1}'", Category, Location);
            ResetFilters(con);
          }
        }
        else if (Location != "-") sql.AppendFormat(@" WHERE Location = '{0}'", Location);
      }
      else
      {
        Category = "-";
        Location = "-";
      }
      return Helper.GetDataTable(con, sql.ToString());
    }
    private void ResetFilters(SqlConnection con)
    {
      var t = Helper.GetDataTable(con, "SELECT DISTINCT Category, Location FROM Fishery");
      var cats = new HashSet<string>();
      var locs = new HashSet<string>();
      foreach (DataRow r in t.Rows)
      {
        var cat = (string)r[0];
        var loc = (string)r[1];
        cats.Add(cat);
        locs.Add(loc);
      }
      Categories = cats;
      Locations = locs;
    }
    private void InitFisheries(SqlConnection con)
    {
      var t = GetData(con);          
      Risks = new Dictionary<int, Risk>();
      FisheriesDictionary = new Dictionary<int, Fishery>();
      EditingDictionary = new Dictionary<int, Risk>();
      var filter = Categories == null;
      HashSet<string> cats, locs;
      if (filter)
      {
        cats = new HashSet<string>();
        locs = new HashSet<string>();
      }
      else
      {
        cats = null;
        locs = null;
      }
      foreach (DataRow r in t.Rows)
      {
        var id = (int)r[0];
        var name = (string)r[1];
        var cat = (string)r[2];
        var loc = (string)r[3];
        var month = (int)r[4];
        var lv = (int)r[5];
        var comment = r[6].ToString();
        Fishery f;
        if (!FisheriesDictionary.TryGetValue(id, out f))
        {
          f = new Fishery(id, name, cat, loc);
          FisheriesDictionary.Add(id, f);
          if (filter)
          {
            cats.Add(cat);
            locs.Add(loc);
          }
        }
        SetRisk(f, month, lv, comment);
      }
      if (filter)
      {
        Categories = cats;
        Locations = locs;
      }
      CheckCurrentMonthData(con);
    }
    private void CheckCurrentMonthData(SqlConnection con)
    {
      foreach (var f in Fisheries)
        if (
          !EditingDictionary.ContainsKey(f.Id) &&
          Helper.ExecSQL
            (con, 
            string.Format(@"INSERT INTO Risk (FisheryID, Month, Risk_Rank) VALUES ({0}, {1}, {2})", f.Id, Month, 0)
            )
          )
        {
          SetRisk(f, Month, 0, null);
        }
    }
    private void Save(SqlConnection con)
    {
      foreach (var k in Request.Form.AllKeys)
        if (k.StartsWith("risklevel"))
        {
          var id = k.Substring(9);
          var lv = Convert.ToInt32(Request[k]);
          var sql = lv > 1 ? 
            string.Format(@"UPDATE Risk SET Risk_Rank = {2}, Comment = '{3}' WHERE FisheryID = {0} AND Month = {1}", id, Month, lv, Request["comment" + id]) : 
            string.Format(@"UPDATE Risk SET Risk_Rank = {2}, Comment = NULL WHERE FisheryID = {0} AND Month = {1}", id, Month, lv);
          Saved |= Helper.ExecSQL(con, sql);
        }
    }
    private void Publish(SqlConnection con)
    {
      var ids = new List<string>();
      foreach (var k in Request.Form.AllKeys)
        if (k.StartsWith("publish")) ids.Add(k.Substring(7));
      var risks = new List<Risk>();
      foreach (var id in ids)
      {
        Fishery fish;
        if (FisheriesDictionary.TryGetValue(Convert.ToInt32(id), out fish))
        {
          var lv = Convert.ToInt32(Request["risklevel" + id]);
          var comment = lv > 1 ? Request["comment" + id] : null;
          risks.Add(new Risk(fish) { RiskLevel = lv, Comment = comment });
        }
      }
      PublishedCount = risks.Count;
      Published = PublishedCount != 0 && PublicService.PublishRisks(con, Convert.ToInt32(Session["UserID"]), risks);
    }

    private void SetRisk(Fishery fish, int month, int risk, string comment)
    {
      var r = new Risk(fish) { RiskLevel = risk, Comment = comment };
      Risks[fish.Id * 100 + month] = r;
      if (month == Month) EditingDictionary[fish.Id] = r;
    }
    public Risk GetRisk(Fishery fish, int month)
    {
      Risk r;
      return Risks.TryGetValue(fish.Id * 100 + month, out r) ? r : NULL;
    }
  }
}